﻿using System;
using System.Collections.Generic;
using Ah.Testudin.Engine.Events;
using Microsoft.Xna.Framework;

namespace Ah.Testudin.Engine.Processes
{
    public class ProcessManager : IProcessManager
    {
        #region Private Methods

        private IList<IProcess> _processes;

        #endregion

        #region Constructors

        public ProcessManager()
        {
            _processes = new List<IProcess>();
        }

        #endregion

        #region IProcessManager

        public void Update(GameTime gameTime)
        {
            IList<IProcess> deadProcesses = new List<IProcess>();

            IList<IProcess> newProcesses = new List<IProcess>();

            foreach (IProcess currentProcess in _processes)
            {
                if (currentProcess.State == ProcessState.Uninitialized)
                {
                    currentProcess.Initialize();
                }

                if (currentProcess.State == ProcessState.Running)
                {
                    currentProcess.Update(gameTime);
                }

                if (currentProcess.IsDead)
                {
                    if (currentProcess.State == ProcessState.Succeeded)
                    {
                        IProcess childProcess = currentProcess.ChildProcess;

                        if (childProcess != null)
                        {
                            newProcesses.Add(childProcess);
                        }
                    }

                    deadProcesses.Add(currentProcess);
                }
            }

            foreach (IProcess currentDeadProcess in deadProcesses)
            {
                _processes.Remove(currentDeadProcess);
            }

            foreach (IProcess currentNewProcess in newProcesses)
            {
                _processes.Add(currentNewProcess);
            }
        }

        public void AttachProcess(IProcess process)
        {
            if (process == null)
            {
                throw new ArgumentNullException("process");
            }

            _processes.Add(process);
        }

        public void AbortAllProcesses(bool immediately)
        {
            IList<IProcess> deadProcesses = new List<IProcess>();

            foreach (IProcess currentProcess in _processes)
            {
                if (currentProcess.IsDead == false)
                {
                    currentProcess.Abort();

                    if (immediately)
                    {
                        deadProcesses.Add(currentProcess);
                    }
                }
            }

            foreach (IProcess currentDeadProcess in deadProcesses)
            {
                _processes.Remove(currentDeadProcess);
            }
        }

        #endregion
    }
}
